#pragma

#include <iostream>
#include <memory>
#include <functional>
#include "Epoller.hpp"
#include "Socket.hpp"
#include "InetAddr.hpp"
#include "log.hpp"
#include "Connection.hpp"
#include "Protocol.hpp"
#include "Reactor.hpp"

using func_t = std::function<std::string(std::string &)>;

class IOService : public Connection
{
    static const int size = 1024;

public:
    IOService(int sockfd)
    {
        SetNonBlocking(sockfd);
        SetSockfd(sockfd);
        SetEvents(EPOLLIN | EPOLLET);
    }
    virtual void Sender() override
    {
        // outbuffer 发送给对方
        // 与读不同，写默认就就绪，所以直接写入，只有当写缓冲区满了才交给epoll托管
        while (true)
        {
            ssize_t n = send(Sockfd(), OutString().c_str(), OutString().size(), 0);
            if (n > 0)
            {
                // 成功
                DisCardOutString(n); // 移除N个
            }
            else if (n == 0)
            {
                break;
            }
            else
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    // 缓冲区写满了
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    Excepter();
                    return;
                }
            }
        }

        // 缓冲区满了
        if (IsOutBufferEmpty())
        {
            // 修改对sockfd的事件关心，开启对写事件的关心
            // 写事件关心不能常开启，必须按需设置
            GetOwner()->EnableReadWrite(Sockfd(), true, true);
        }
        else
        {
            GetOwner()->EnableReadWrite(Sockfd(), true, false);
        }
    }
    virtual void Recever() override
    {
        // 1. 读取所有数
        while (true)
        {
            char buffer[size];
            ssize_t s = recv(Sockfd(), buffer, sizeof(buffer) - 1, 0);
            if (s > 0)
            {
                buffer[s] = 0;
                Append(buffer);
            }
            else if (s == 0)
            {
                // 对端关闭连接
                Excepter();
                return;
            }
            else
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    Excepter();
                    return;
                }
            }
        }
        std::cout << "outbuffer: \n"
                  << InBuffer() << std::endl;

        std::string result;
        if (_on_message)
        {
            result = _on_message(InBuffer());
        }
        AppendToOut(result);

        if (!IsOutBufferEmpty())
            Sender();
    }

    virtual void Excepter() override
    {
        // IO异常处理
        GetOwner()->DelConnection(Sockfd());
    }

    void RegisterOnMessage(func_t on_message)
    {
        _on_message = on_message;
    }

    ~IOService()
    {
    }

private:
    func_t _on_message;
};